#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>
#include <pthread.h>

#include "estructuras.h"
#include "constantes.h"
#include "sockets.h"
#include "configuracion.h"
#include "estadisticas.h"
#include "listas.h"
#include "NIPC.h"

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

extern chs glChs;
extern int glRPM;
extern int ALG;
extern int MODO;
extern char *data;

extern int posicionCabezal;
int activaEnAtencion;

void * AtenderPedido (void *args); 

void * AtenderPedido (void *args)
{
	int *pSocketConectado;
	sectoresIntermedios listaSectoreYTiempos;
	int f,i,payload,j;
	int ret;
	int sectoresEscritos=0;
	int cont=0;
	
	colas2 *q = (colas2 *) args;
	char *sSocket=(char *)malloc(10);
	char *auxread=(char *)malloc(512);
	char *sSector=(char *)malloc(20);
	char *sAux=(char *)malloc(20);

	while(1)
	{		
		if(!(estaVacia(q->activacabeza))){
			
			if(ALG==2)
				activaEnAtencion=1;
			
			struct ListaIDdescriptors * nodoaAtender;
		
			
			if(ret=pthread_mutex_trylock(&mutex)){
			
			
			nodoaAtender=SacarNodoDescriptoresDeLista(&q->activacabeza,&q->activacola);
			
			if(pthread_mutex_unlock(&mutex)!=0){
					perror("pthread_mutex_unlock");
					exit(EXIT_FAILURE);
			}
			
			/*
			listaSectoreYTiempos = SectoresIntermedios_Actualiza(&posicionCabezal,nodoaAtender->sector,glChs,glRPM);
			printf("SECTORES LEIDOS: ");
			for( f = 0;f < listaSectoreYTiempos.tamanioVector;f++)
			{
				printf("%d |", listaSectoreYTiempos.ptrSectoresLeidos[f]);
			}
			printf("\n");

			printf("TIEMPO CONSUMIDO: %f ms\n",listaSectoreYTiempos.tiempoDeAcceso);
			*/
			
			
			memset(sAux,'\0',20);
			intacad(nodoaAtender->sector, sAux);	
			
			
			
			
			if((nodoaAtender->operacion == 0)||(nodoaAtender->operacion == 2))
			{
				
				
				if((nodoaAtender->operacion == 0)){
					printf("Leer Sector: %i \n", nodoaAtender->sector);
					payload=RTA_READ_SECTOR_REQUEST;
					
				}	
				else{
					/*printf("Leer Sector SYNC: %i\n", nodoaAtender->sector);*/
					payload=RTA_READ_SECTORSYNC_REQUEST;
					
				}
				memset(auxread,'\0',512);
				memcpy(auxread,readSector(nodoaAtender->sector), 512);
				/*printf("\nDATA LEIDA\n");
				printf("----------\n");
				for(j=0;j<512;j++)
					printf("%c", auxread[j]);
				printf("----------\n");
				*/
				
				
				if(MODO==1)
				{
					
					int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1 + 512 +1;
					char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
					memset(buffer,'\0',tamanio_buff);
					strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
					strcat(buffer, ",");
					strcat(buffer, sAux);
					strcat(buffer, ";");
					
					memcpy(buffer + strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1, auxread, 512);
					/*memcpy(buffer + strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1 + 512, "\0", 1);*/ 
					
						
					InfoIPC rInfoIPC3;
					rInfoIPC3.payLoadLength=tamanio_buff;
					generarStructIPC(buffer,payload,&rInfoIPC3);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);	
					
					free(rInfoIPC3.payload);
					free(buffer);
					
					sectoresEscritos++;
					
					
					if(sectoresEscritos%100000==0){
						printf("Se sincronizaron %i \n",sectoresEscritos);
						if(cont == 0)
							msync(data, 100000*512, MS_SYNC);
						else
							msync(data + ((sectoresEscritos - 100000) * 512), 100000*512, MS_SYNC);
						cont++;
					}
					
				}
				else{
				
					/*Le envio al cliente FSS el numero de sector respondido*/
					InfoIPC rInfoIPC3;
					rInfoIPC3.payLoadLength= strlen(sAux) + 1;
					generarStructIPC(sAux ,payload,&rInfoIPC3);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);
					
					free(rInfoIPC3.payload);
			
					
					/*Le envio al cliente FSS la data correspondiente*/
					InfoIPC rInfoIPC4;
					rInfoIPC4.payLoadLength=512;
					generarStructIPC(auxread,payload,&rInfoIPC4);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC4);				
				
					free(rInfoIPC4.payload);
					
					printf("Tras enviar la data correspondiente \n");
				}
				/*
				InfoIPC infoIPC3;
				infoIPC3.payLoadLength=512;
				generarStructIPC(auxread,payload,&infoIPC3);
				enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&infoIPC3);	*/
				
			
				
				
			}
			if((nodoaAtender->operacion == 1)||(nodoaAtender->operacion == 3))
			{
				

				if((nodoaAtender->operacion == 1)){
					printf("Escribir Sector: %i - %s\n", nodoaAtender->sector, nodoaAtender->data);	
					payload=RTA_WRITE_SECTOR_REQUEST;
				}	
				else{
					/*printf("Escribir SectorSYNC: %i - %s\n", nodoaAtender->sector, nodoaAtender->data);*/
					sectoresEscritos++;
					payload=RTA_WRITE_SECTORSYNC_REQUEST;
				}
				
				writeSector(nodoaAtender->sector, nodoaAtender->data);
				
				
				if(MODO==1){
				
					if(strcmp(nodoaAtender->sDescriptorID_delPedido,"-1")){
	
						int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 2 ;
						char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
					
						strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
						strcat(buffer, ",");
						strcat(buffer, sAux);
						strcat(buffer, ";");
						
						InfoIPC rInfoIPC6;
						rInfoIPC6.payLoadLength=tamanio_buff;
						generarStructIPC(buffer,payload,&rInfoIPC6);
						enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC6);	
						
						free(rInfoIPC6.payload);
						free(buffer);
					}	
					else{
					
						if(sectoresEscritos%100000==0)
							printf("Se sincronizaron %i \n",sectoresEscritos);
						
						if(sectoresEscritos==1048575){
						
							msync(data,512*sectoresEscritos, MS_SYNC);
							
							int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 2 ;
							char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
						
							strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
							strcat(buffer, ",");
							strcat(buffer, sAux);
							strcat(buffer, ";");
							
							InfoIPC rInfoIPC6;
							rInfoIPC6.payLoadLength=tamanio_buff;
							generarStructIPC(buffer,FINSINCRO,&rInfoIPC6);
							enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC6);	
							
							free(rInfoIPC6.payload);
							free(buffer);
							
						}	
					}
				
				}
				else{
					InfoIPC rInfoIPC5;
					rInfoIPC5.payLoadLength= strlen(sAux) + 1;
					generarStructIPC(sAux,payload,&rInfoIPC5);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC5);
					free(rInfoIPC5.payload);
				}
			}
					
			posicionCabezal=nodoaAtender->sector + 1;		
			free(nodoaAtender);		
			
		}	
		}
		else{
			
			if(ALG==2){
				if(!(estaVacia(q->pasivacabeza))){
					
					activaEnAtencion=0;
					
					while(q->pasivacabeza!=NULL){
					
						struct ListaIDdescriptors* nodo;
						
						if(pthread_mutex_lock(&mutex2)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}
						if(pthread_mutex_lock(&mutex)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}
						
						nodo=SacarNodoDescriptoresDeLista(&q->pasivacabeza,&q->pasivacola);
						AgregarAColaDePedidosADisco(&nodo,&q->activacabeza,&q->activacola);  
						
						if(pthread_mutex_unlock(&mutex)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}
						if(pthread_mutex_unlock(&mutex2)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}	
					}		
				}
			}
		}
	}	
}